use std::any::Any;
use std::sync::Arc;
use crate::actor::ActorRef;
mod header;
pub use header::MessageHeader;

#[derive(Clone)]
pub struct Message<T: Any + Send + Clone + 'static> {
    payload: Arc<T>,
    sender: Option<ActorRef>,
    header: Option<MessageHeader>,
    priority: u8,
}

#[derive(Clone)]
pub struct DynamicMessage {
    payload: Arc<Box<dyn Any + Send + Sync>>,
    sender: Option<ActorRef>,
    header: Option<MessageHeader>,
    priority: u8,
}

impl<T: Any + Send + Clone + 'static> Message<T> {
    pub fn new(payload: T) -> Self {
        Self {
            payload: Arc::new(payload),
            sender: None,
            header: None,
            priority: 0,
        }
    }

    pub fn with_sender(mut self, sender: ActorRef) -> Self {
        self.sender = Some(sender);
        self
    }

    pub fn with_header(mut self, header: MessageHeader) -> Self {
        self.header = Some(header);
        self
    }

    pub fn with_priority(mut self, priority: u8) -> Self {
        self.priority = priority;
        self
    }

    pub fn into_dynamic(self) -> DynamicMessage {
        DynamicMessage {
            payload: Arc::new(Box::new((*self.payload).clone())),
            sender: self.sender,
            header: self.header,
            priority: self.priority,
        }
    }
}

impl DynamicMessage {
    pub fn downcast<T: Any + Send + Clone + 'static>(&self) -> Option<T> {
        self.payload.downcast_ref::<T>().cloned()
    }

    pub fn sender(&self) -> Option<&ActorRef> {
        self.sender.as_ref()
    }

    pub fn header(&self) -> Option<&MessageHeader> {
        self.header.as_ref()
    }

    pub fn priority(&self) -> u8 {
        self.priority
    }
} 